﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Collections;
using PMisuseAn.io;

namespace PMisuseAn.behaviour.model
{
    public class HHenceforthSatisfactionTest
    {
        public static bool satisfiedAnalysis(Agent sendAgent, Agent receiveAgent, Agent subjectAgent,
                                    ListDictionary tokenisedContent, Context contextInstance, int intSeqNo)
        {
            ListDictionary contextItems = new ListDictionary();
            ListDictionary aggContextItems = new ListDictionary();
            string temporalConstraint = "";

            int newKey = HistorySerialisationEngine.totalInteractions();
            bool satisfiedThenSegment = false;

            //Stack<string> stackedInteractionNames = HistorySerialisationEngine.getStackedInteractionList();
            Stack<int> interactionSeqNos = HistorySerialisationEngine.getStackedInteractionList();
            foreach (int interactionSeqNo in interactionSeqNos)
            {
                //int h_intSeqNo = VulnerabilityAnalyser.retrieveInteractionSeqNo(interactionSeqNo);
                int h_intSeqNo = interactionSeqNo;
                if (h_intSeqNo < intSeqNo)
                {
                    continue;
                }

                HistoryItem ih = HistorySerialisationEngine.deSerialiseInteractionHistory(interactionSeqNo, EmulationEnvironmentWindow.sourceAgentName);
                int counter = 0;
                while (ih == null && counter < 4)
                {
                    ih = HistorySerialisationEngine.deSerialiseInteractionHistory(interactionSeqNo, EmulationEnvironmentWindow.sourceAgentName);
                    counter++;
                } 
                
                ListDictionary hi = ih.interactionHistoryItem;
                //foreach (KeyValuePair<List<Object>, Dictionary<Dictionary<Agent, Agent>, ListDictionary>> historyItem in hi)
                foreach (DictionaryEntry historyItem in hi)
                {
                    List<Object> parameterisedContextInstances = (List<Object>)historyItem.Key;
                    Dictionary<Dictionary<Agent, Agent>, ListDictionary> sendReceiveContextAgent = (Dictionary<Dictionary<Agent, Agent>, ListDictionary>)historyItem.Value;

                    State message_s = null;
                    Transition message_t = null;
                    Agent h_sendAgent = null;
                    Agent h_receiveAgent = null;
                    Agent h_subjectAgent = null;

                    foreach (KeyValuePair<Dictionary<Agent, Agent>, ListDictionary> pairx in sendReceiveContextAgent)
                    {
                        Dictionary<Agent, Agent> messageHeader = pairx.Key;
                        foreach (KeyValuePair<Agent, Agent> sr in messageHeader)
                        {
                            h_sendAgent = sr.Key;
                            h_receiveAgent = sr.Value;
                        }

                        ListDictionary messageBody = pairx.Value;
                        foreach (DictionaryEntry mes in messageBody)
                        {
                            h_subjectAgent = (Agent)mes.Key;
                            if (mes.Value is State)
                            {
                                message_s = (State)mes.Value;
                                message_t = null;
                            }
                            else if (mes.Value is Transition)
                            {
                                message_t = (Transition)mes.Value;
                                message_s = null;
                            }
                        }

                        if (sendAgent.agentName.Equals(h_sendAgent.agentName) &&
                            receiveAgent.agentName.Equals(h_receiveAgent.agentName) &&
                            subjectAgent.agentName.Equals(h_subjectAgent.agentName))
                        {
                            bool attributeFunctionActive = false;
                            bool groupFunctionActive = false;

                            string lastEntity = "";
                            string lastEntityType = "";
                            string joinOperator = "";
                            string symbol = "";

                            foreach (DictionaryEntry policyItem in tokenisedContent)
                            {
                                int pol_id = (int)policyItem.Key;

                                Dictionary<string, string> word_m = (Dictionary<string, string>)policyItem.Value;

                                foreach (KeyValuePair<string, string> pair in word_m)
                                {
                                    string type = pair.Key;
                                    string word = pair.Value;
                                    if (type.Equals("functionalAttribute"))
                                    {
                                        bool found = false;
                                        if (message_s != null)
                                        {
                                            if (message_s.name.Equals(word))
                                            {
                                                attributeFunctionActive = true;
                                                contextItems.Add(newKey, true);
                                                newKey = newKey + 1;
                                                found = true;
                                                lastEntity = word;
                                                lastEntityType = type;
                                            }
                                        }
                                        else if (message_t != null)
                                        {
                                            string endState = message_t.endState;
                                            if (endState.Equals(word))
                                            {
                                                attributeFunctionActive = true;
                                                found = true;
                                                contextItems.Add(newKey, true);
                                                newKey = newKey + 1;
                                                lastEntity = word;
                                                lastEntityType = type;
                                            }
                                        }

                                        if (!found)
                                        {
                                            contextItems.Add(newKey, false);
                                            newKey = newKey + 1;
                                        }
                                    }
                                    else if (type.Equals("temporalconstraint"))
                                    {
                                        contextItems.Add(newKey, true);
                                        temporalConstraint = word;
                                        newKey = newKey + 1;
                                    }
                                    else if (type.Equals("attribute"))
                                    {
                                        bool found = false;
                                        foreach (Object obj in parameterisedContextInstances)
                                        {
                                            Attribute att = obj as Attribute;
                                            if (att != null)
                                            {
                                                if (att.name.Equals(word))
                                                {

                                                    contextItems.Add(newKey, true);
                                                    newKey = newKey + 1;
                                                    found = true;
                                                    lastEntity = word;
                                                    lastEntityType = type;
                                                    break;
                                                }
                                            }
                                        }
                                        if (!found)
                                        {
                                            contextItems.Add(pol_id, false);
                                        }
                                    }
                                    else if (type.Equals("number"))
                                    {
                                        double number;
                                        if (Double.TryParse(word, out number))
                                        {
                                            double word_val = Convert.ToDouble(word);

                                            if (lastEntityType.Equals("attribute"))
                                            {
                                                bool found = false;
                                                foreach (Object obj in parameterisedContextInstances)
                                                {
                                                    Attribute att = obj as Attribute;
                                                    if (att != null)
                                                    {
                                                        if (symbol.Equals("="))
                                                        {
                                                            if (att.name.Equals(lastEntity))
                                                            {
                                                                if (Double.TryParse(att.activeDomain, out number))
                                                                {
                                                                    double att_dom_val = Convert.ToDouble(att.activeDomain);
                                                                    if (att_dom_val == word_val)
                                                                    {
                                                                        contextItems.Add(newKey, true);
                                                                        newKey = newKey + 1;
                                                                        found = true;
                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        else if (symbol.Equals("≠"))
                                                        {
                                                            if (att.name.Equals(lastEntity))
                                                            {
                                                                if (Double.TryParse(att.activeDomain, out number))
                                                                {
                                                                    double att_dom_val = Convert.ToDouble(att.activeDomain);
                                                                    if (att_dom_val != word_val)
                                                                    {
                                                                        contextItems.Add(newKey, true);
                                                                        newKey = newKey + 1;
                                                                        found = true;
                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                        else if (symbol.Equals("&lt;"))
                                                        {
                                                            if (att.name.Equals(lastEntity))
                                                            {
                                                                if (Double.TryParse(att.activeDomain, out number))
                                                                {
                                                                    double att_dom_val = Convert.ToDouble(att.activeDomain);
                                                                    if (att_dom_val < word_val)
                                                                    {
                                                                        contextItems.Add(newKey, true);
                                                                        newKey = newKey + 1;
                                                                        found = true;
                                                                        break;
                                                                    }
                                                                }

                                                            }
                                                        }
                                                        else if (symbol.Equals(">"))
                                                        {
                                                            if (att.name.Equals(lastEntity))
                                                            {
                                                                if (Double.TryParse(att.activeDomain, out number))
                                                                {
                                                                    double att_dom_val = Convert.ToDouble(att.activeDomain);
                                                                    if (att_dom_val > word_val)
                                                                    {
                                                                        contextItems.Add(newKey, true);
                                                                        newKey = newKey + 1;
                                                                        found = true;
                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                                if (!found)
                                                {
                                                    contextItems.Add(newKey, false);
                                                    newKey = newKey + 1;
                                                }
                                            }
                                        }
                                    }

                                    else if (type.Equals("string"))
                                    {
                                        bool found = false;
                                        if (lastEntityType.Equals("attribute"))
                                        {
                                            foreach (Object obj in parameterisedContextInstances)
                                            {
                                                Attribute att = obj as Attribute;
                                                if (att != null)
                                                {
                                                    if (symbol.Equals("="))
                                                    {
                                                        if (att.name.Equals(lastEntity))
                                                        {
                                                            if (att.activeDomain.Equals(word))
                                                            {
                                                                contextItems.Add(newKey, true);
                                                                newKey = newKey + 1;
                                                                found = true;
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    else if (symbol.Equals("≠"))
                                                    {
                                                        if (att.name.Equals(lastEntity))
                                                        {
                                                            if (!att.activeDomain.Equals(word))
                                                            {
                                                                contextItems.Add(newKey, true);
                                                                newKey = newKey + 1;
                                                                found = true;
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        else if (lastEntityType.Equals("receiver"))
                                        {
                                            //foreach (Object obj in parameterisedContextInstances)
                                            //{
                                                if (symbol.Equals("="))
                                                {
                                                    if (h_receiveAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                                else if (symbol.Equals("≠"))
                                                {
                                                    if (!h_receiveAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                            //}
                                        }
                                        else if (lastEntityType.Equals("sender"))
                                        {
                                            //foreach (Object obj in parameterisedContextInstances)
                                            //{
                                                if (symbol.Equals("="))
                                                {
                                                    if (h_sendAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                                else if (symbol.Equals("≠"))
                                                {
                                                    if (!h_sendAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                            //}
                                        }
                                        else if (lastEntityType.Equals("subject"))
                                        {
                                            //foreach (Object obj in parameterisedContextInstances)
                                            //{
                                                if (symbol.Equals("="))
                                                {
                                                    if (h_subjectAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                                else if (symbol.Equals("≠"))
                                                {
                                                    if (!h_subjectAgent.agentName.Equals(word))
                                                    {
                                                        contextItems.Add(newKey, true);
                                                        newKey = newKey + 1;
                                                        found = true;
                                                        //break;
                                                    }
                                                }
                                            //}
                                        }
                                        if (!found)
                                        {
                                            contextItems.Add(newKey, false);
                                            newKey = newKey + 1;
                                        }
                                    }
                                    else if (type.Equals("and"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        joinOperator = word;
                                        aggContextItems.Add(contextItems, word);
                                        contextItems = new ListDictionary();
                                    }
                                    else if (type.Equals("or"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        joinOperator = word;
                                        aggContextItems.Add(contextItems, word);
                                        contextItems = new ListDictionary();
                                    }
                                    else if (type.Equals("sender"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        lastEntityType = type;
                                        lastEntity = word;
                                    }
                                    else if (type.Equals("lessthan") || type.Equals("greaterthan") || type.Equals("equals") || type.Equals("notequals"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        symbol = word;
                                    }
                                    else if (type.Equals("receiver"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        lastEntityType = type;
                                        lastEntity = word;
                                    }
                                    else if (type.Equals("subject"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                        lastEntityType = type;
                                        lastEntity = word;
                                    }
                                    else if (type.Equals("groupFunction"))
                                    {
                                        bool found = false;
                                        foreach (Object obj in parameterisedContextInstances)
                                        {
                                            //TODO: groupfunction functional check

                                            GroupFunction gf = obj as GroupFunction;
                                            if (gf != null)
                                            {
                                                if (gf.functionName.Equals(word))
                                                {
                                                    groupFunctionActive = true;
                                                    contextItems.Add(newKey, true);
                                                    newKey = newKey + 1;
                                                    found = true;
                                                    lastEntityType = type;
                                                    lastEntity = word;
                                                    break;
                                                }
                                            }
                                        }
                                        if (!found)
                                        {
                                            contextItems.Add(newKey, false);
                                            newKey = newKey + 1;
                                        }
                                    }
                                    else if (type.Equals("openingBracket"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                    }
                                    else if (type.Equals("comma"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                    }
                                    else if (type.Equals("closingBracket"))
                                    {
                                        if (attributeFunctionActive)
                                        {
                                            attributeFunctionActive = false;
                                        }
                                        else if (groupFunctionActive)
                                        {
                                            groupFunctionActive = false;
                                        }

                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;

                                    }
                                    else if (type.Equals("closingsquarebracket"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                    }
                                    else if (type.Equals("openingsquarebracket"))
                                    {
                                        contextItems.Add(newKey, true);
                                        newKey = newKey + 1;
                                    }
                                }
                            }
                            if (aggContextItems.Contains(contextItems))
                            {
                                ListDictionary dic = new ListDictionary();
                                foreach (DictionaryEntry pair in contextItems)
                                {
                                    dic.Add(pair.Key, pair.Value);
                                }
                                aggContextItems.Add(dic, "NOJOIN");

                            }
                            else
                            {
                                aggContextItems.Add(contextItems, "NOJOIN");

                            }
                        }
                    }
                }

            }

            foreach (DictionaryEntry contextItemkv in aggContextItems)
            {
                ListDictionary contextItem = (ListDictionary)contextItemkv.Key;
                string jointype = (string)contextItemkv.Value;
                bool fault = false;
                foreach (DictionaryEntry item in contextItem)
                {
                    bool val = (bool)item.Value;
                    if (val == false)
                    {
                        fault = true;
                    }
                }
                if (fault == false)
                {
                    satisfiedThenSegment = true;
                }
                else
                {
                    satisfiedThenSegment = false;
                }

                if (jointype.Equals("∧") && satisfiedThenSegment == false)
                {
                    break;
                }
                else if (jointype.Equals("∧") && satisfiedThenSegment == true)
                {
                    //continue;
                }
                else if (jointype.Equals("V") && satisfiedThenSegment == true)
                {
                    break;
                }
                else if (jointype.Equals("V") && satisfiedThenSegment == false)
                {
                    //continue;
                }
            }

            //if (satisfiedThenSegment == true)
            //{
            //    break;
            //}
            //else
            //{
            //    aggContextItems = new ListDictionary();
            //}

            return satisfiedThenSegment;
        }
    }
}

